#include "vxmovement.h"

class MouseCaptureTransition : public QMouseEventTransition
{
	Q_OBJECT
public:
	MouseCaptureTransition(QWidget * widget):
			QMouseEventTransition(widget, QEvent::MouseButtonPress, Qt::LeftButton),
			_widget(widget)
	{
	}


	void onTransition(QEvent *event)
	{
		if (event->type() != QEvent::StateMachineWrapped){
			return;
		}

		QStateMachine::WrappedEvent * wrapped = static_cast<QStateMachine::WrappedEvent *>(event);

		if (wrapped->event()->type() != QEvent::MouseButtonPress){
			return;
		}

		QMouseEvent * mevent = static_cast<QMouseEvent *>(wrapped->event());

		QPoint p = mevent->globalPos() -
				   _widget->parentWidget()->mapToGlobal(_widget->geometry().topLeft());

		_widget->setProperty("_mpoint", p);
	}

private:
	QWidget * _widget;
};


class MouseMoveTransition : public QMouseEventTransition
{
	Q_OBJECT
public:
	MouseMoveTransition(QWidget * widget) :
			QMouseEventTransition(widget, QEvent::MouseMove, Qt::NoButton),
			_widget(widget)
	{
	}

	void onTransition(QEvent *event)
	{
		if (event->type() != QEvent::StateMachineWrapped){
			return;
		}

		QStateMachine::WrappedEvent * wrapped = static_cast<QStateMachine::WrappedEvent *>(event);

		if (wrapped->event()->type() != QEvent::MouseMove){
			return;
		}

		QMouseEvent * me = static_cast<QMouseEvent *>(wrapped->event());

		QPoint mp = _widget->property("_mpoint").toPoint() +
						_widget->parentWidget()->mapToGlobal(_widget->geometry().topLeft());

		QPoint p = me->globalPos() - mp;


		emit movement(p.x(), p.y());

	}

signals:
	void movement(int mx, int my);
	void immobility();

private:
	QWidget * _widget;

};


VxMovement::VxMovement(QWidget * widget) :
		QStateMachine(widget)
{
	QState * stImmobility = new QState();
	QState * stMouseCapture = new QState();
	QState * stMouseMovement = new QState();

	this->addState(stImmobility);
	this->addState(stMouseCapture);
	this->addState(stMouseMovement);

	MouseCaptureTransition * trMouseDown = new MouseCaptureTransition(widget);
	trMouseDown->setTargetState(stMouseCapture);

	QMouseEventTransition * trMouseCaptureToRelease = new QMouseEventTransition(widget, QEvent::MouseButtonRelease, Qt::LeftButton);
	trMouseCaptureToRelease->setTargetState(stImmobility);

	QMouseEventTransition * trMouseCaptureToMove = new QMouseEventTransition(widget, QEvent::MouseMove, Qt::NoButton);
	trMouseCaptureToMove->setTargetState(stMouseMovement);

	QMouseEventTransition * trMouseMoveToRelease = new QMouseEventTransition(widget, QEvent::MouseButtonRelease, Qt::LeftButton);
	trMouseMoveToRelease->setTargetState(stImmobility);

	MouseMoveTransition * trMouseMoveToMove = new MouseMoveTransition(widget);


	stImmobility->addTransition(trMouseDown);
	stMouseCapture->addTransition(trMouseCaptureToRelease);
	stMouseCapture->addTransition(trMouseCaptureToMove);

	stMouseMovement->addTransition(trMouseMoveToRelease);
	stMouseMovement->addTransition(trMouseMoveToMove);

	this->setInitialState(stImmobility);

	connect(trMouseMoveToMove, SIGNAL(movement(int,int)), this, SLOT(_movement(int,int)));
	connect(stImmobility, SIGNAL(entered()), this, SLOT(_immobilityEntered()));
	connect(stImmobility, SIGNAL(exited()), this, SLOT(_immobilityExited()));

}

void VxMovement::_movement(int mx, int my)
{
	emit movement(mx, my);
}

void VxMovement::_immobilityEntered()
{
	emit immobility();
}

void VxMovement::_immobilityExited()
{
	emit immobilityLost();
}

#include "vxmovement.moc"
